Redux ,尽管是目前前端界最火的库之一,但是还是有很多人对它有些困惑:它到底是个啥,用了它又有什么好处。
正如官方文档陈述一样,Redux是用来存放javascript 应用状态的容器,并且是可预测的。换句话说,它是一个应用程序的数据流架构,区别于像Underscore.js或者AngularJs 这样的js库和框架。
Redux诞生于2015年6月,作者Dan Abramov。他的灵感来源于Facebook的Flux 和 函数式编程语言Elm。因为简单、体积小(才2kb大小)和丰富的文档资料,它迅速在前端界流行起来。如果你想学习Redux的内部工作原理并且深入研究它,可以考虑看下 Dan 的免费课程。
Redux大部分是用来作为应用的状态管理器。总的来说,Redux将整个应用的状态保存在一个不可变的状态树(对象)上,就是不能直接改变它,必须通过一些方法(action&reducers)去告知它改变。下面我们将详细的去探讨这些。
与MVC、Flux的差异
首先说一下MVC:model-view-controller 模式, 大多数程序员都对此很熟悉,在MVC结构中,数据层(model)、展现层(view)和 逻辑层(controller)都很有明显的界限,各司其职。但它存在一个问题,特别是在大型应用中,就是数据流是双向的。这意味着一个变化(可能是用户的输入或者接口返回)可能会影响到整个应用的状态:比如双向绑定。这会导致我们很难知道状态是从那儿来的,调试都很为难。
再说下Flux, 它和Redux非常的相似。差别在于:
- Flux可以有很多store来改变应用的状态,以事件方式去广播(告知)这些改变。而组件则可以订阅事件去同步最新的状态。Redux并没有这样的分发器(dispatcher),而Flux正是通过分发器去广播这些改变来注册回调事件
- Flux衍生出来的有太多种类了,由此会对开发者们产生一些困惑和不一致性
Redux带来的好处
你或许会问“为啥我要用Redux ”, 好问题!(尼玛外国人写文章都是这样的吗),下面就列举下 Redux会给你下一个应用能带来的好处:
- 可预测性
只有唯一的数据源:唯一的store,这样就不会困惑于:这状态tm哪儿来的。只需要通过活动去同步状态就好。 - 可维护性
结果可预测和严谨的架构让代码维护更加简单。 - 可组织性
Redux有着严格的代码规范,这样出来的代码更加一致,方便团队去一起维护。 - 服务端渲染
这真的很有用,特别在初始化页面渲染的时候,这会提升用户体验和优化搜索引擎。直接通过服务器端创建store,然后传递给客户端。 - 强大的开发者工具
开发者通过它可以实时监控着整个应用的 活动到状态的改变。 - 社区生态
强大的社区支持,你学习或者使用任何库和框架都能得到各种各样的支持。 - 可测试性
编写可测试代码的第一条规则是写独立的小函数并且只做一件事。编写Redux代码,就是这样:小,纯 ,独!
函数式编程
曾经提到过,Redux是完全建立在函数式编程之上的。这些概念对于理解Redux如何工作以及为什么这样是非常重要的。下面我们回顾下函数式编程的基本概念:
- 函数是第一等对象
- 传参就是函数
- 通过函数、递归和数组来控制流程
- 比如采用用纯净函数、递归函数、 高阶函数、闭包和匿名函数
- 比如采用辅助函数,比如map,filter和reduce.
- 可以将函数连接在一起
- 状态不可变
- 不关注代码执行顺序
函数编程可以让我们写出更加纯净和模块化的代码。在流程和逻辑层上编写小而简单的代码,也让代码测试,维护和调试更加简单,同时这些小代码也都是可复用的,这样代码量也会下降,这的确很棒。这些函数不需要任何修改就可以复制粘贴到任何地方使用。函数在应用中都是隔离的,只会执行自己的代码,不会依赖其他模块,这样就减少了代码之间的耦合性。
你将会看到纯函数、匿名函数、闭包、高阶函数和方法链在函数式javascript的广泛使用。 Redux广泛的使用纯函数,理解它们也是非常重要的。
“纯函数”:会根据传给它的参数而返回一个全新的值。也就是说它不会修改现有的对象,而是返回一个全新的。它也不依赖传进来的状态,且只会返回和入参一样的结果。因此,它也是可预测的。
因为纯函数不会修改任何值,它也不会对整个作用域有任何影响或副作用,这也就意味着开发者只需要关心纯函数所返回出来的值。
Redux可以用在哪儿
大部分开发者会将React 和Redux 联系在一起,但实际上,它可以和任何一个js视图库 配合使用。比如 AngularJS,Vue.js,Polymer,Ember,Backbone.js 和 Meteor。 但Redux和React还是最普遍的组合。确保按正确的顺序去学习React: 这里我推荐前FaceBook员工Pete Hunt`s 的学习曲线,这十分适合刚开始学习React的开发者。不管是新手还是很有经验的前端开发者都会有“JS疲劳症”,所以用正确的方式以及正确的顺序来学习React和Redux 也是十分重要的。
Redux之所以比较惊艳的原因之一是因为它背后建立起来的生态:有关它的文章,教程,中间件,开发者工具和脚手架超级之多。就个人而言,我经常使用David Zukowski`s的脚手架,因为它包含了需要开发一个React应用的所有东西(React ,Redux和React router)。但同时我也要做个提醒:在学一个新框架(比如React和Redux)的时候还是不要使用脚手架或者新手包之类的,它会让你在使用的时候更加困惑,“我擦,为啥这样用!”会时常在里心里迸发出的一句话,因为你不知道它是怎么一起工作的。相反,我建议大家一步一步的从一个小的应用开始熟悉框架,最后再使用脚手架工具来提高开发效率。
Redux结构
Redux概念或许听起来比较复杂或者华而不实,但它其实是很简单的。记住它才2kb。Redux有3个组成部份:actions , store 和 reducers。
看着上面的图 我们来一一看看每个部分的作用
Actions
简而言之,actions(活动)其实就是事件。actions会将(由用户交互,内部事件或者表单提交)所产生的数据发送给store。并且store 只从actions获取信息。内部actions的结构是简单的json对象,它有一个type字段(通常是一个常量)来表述这个事件的类型,和需要发给store 的数据信息。1
2
3
4{
type: LOGIN_FORM_SUBMIT,
payload: {username: ‘alex’, password: ‘123456’}
}Actions 是actions creators所生成,其实就是能返回actions的函数:
1
2
3
4
5
6function authUser(form) {
return {
type: LOGIN_FORM_SUBMIT,
payload: form
}
}在应用中触发actions就更简单了,用dispatch方法就可以了,如下:
dispatch(authUser(form));
Reducers
我们已经讨论了在函数式javascript中的reducer是什么。 它是基于数组的reduce(累加器)方法:接收一个回调函数,可以将数组中的值合并变为一个值返回给你。在Redux里,reducers 是一个纯函数,它接收到一个应用state(状态)和一个action(活动),然后返回一个新的state(状态)。理解reducers是如何工作是非常重要的,因为他们占据了redux 中大部分工作。下面是一个非常简单的例子:1
2
3
4
5function handleAuth(state, action) {
return Object.assign({}, state, {
auth: action.payload
});
}对于一些更加复杂的应用,可以使用Redux自带的combineReducers()方法来把所有的reducers合并成一个 主reducer,同时保持每个reducers的独立性。这样维护起来也十分方便。
如果状态树某些值改变了,Redux会生成一个新的对象,它不会改变之前的值,而是生成全新的值,这个很强大!如果你想它更有效,你可以试试增加一个 Immutable.js.的库。1
2
3
4
5const rootReducer = combineReducers({
handleAuth: handleAuth,
editProfile: editProfile,
changePassword: changePassword
});Store
Store顾名思义就是商店,它用来保存应用状态 同时 也提供一些辅助方法用来获取状态,分发活动和注册事件。整个应用状态只会保存在唯一的store树上。任何action只能通过reducers来返回新的状态。这样使得Redux变得简单和可预测!1
2
3
4import { createStore } from ‘redux’;
let store = createStore(rootReducer);
let authInfo = {username: ‘alex’, password: ‘123456’};
store.dispatch(authUser(authInfo));
开发者工具,实时监控 和 热加载
- react-devtools 可以直接从chrome商店直接安装,当你需要调试的适合在你的审视台中就能看见.
- redux-devtools则是一个插件,当你开启的时候会显示在你的页面右侧,你可以实时的监测到所有的状态变化,活动改变,甚至可以重置,撤销状态!就和使用git一样。
- 通过热加载 你则可以改变代码的同时 实现 页面自动刷新~
如下图(与此文章无关)